﻿using _80X_CG_Frame.Utils;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

namespace _80X_CG_Frame.Objects
{
    /// <summary>
    /// 异步连接的TcpClient, 有连接状态改变事件
    /// </summary>
    public class AsyncClient : INotifyPropertyChanged
    {
        protected TcpClient client;
        private bool isConnect;
        protected NetworkStream ns;

        public bool IsConnect
        {
            get
            {
                if (isConnect != ClientIsConnect())
                {
                    isConnect = ClientIsConnect();
                    NotifyPropertyChanged();
                }
                return isConnect;
            }
            set => isConnect = value;
        }
        public AsyncClient()
        {
            IsConnect = false;
            
            client = new TcpClient();
            client.ReceiveTimeout = 1000;
            client.SendTimeout = 1000;
            
        }
        public async Task<bool> ConnectAsync(string address, int times = 5)
        {
            if(client == null)
                client = new TcpClient();
            if (!IsConnect)
            {
                DisConnect();
                client = new TcpClient();
                client.ReceiveTimeout = 1000;
                client.SendTimeout = 1000;
                string[] addresses = address.Split(':');
                if (addresses.Length != 2)
                {
                    throw new FormatException("地址格式不正确");
                }
                else
                {
                    bool connected = await TcpAsyncConnect.ConnectAsync(
                        client,
                        addresses[0],
                        Convert.ToInt32(addresses[1]),
                        times);
                    if (IsConnect)
                    {
                        ns = client.GetStream();
                        ns.ReadTimeout = 1000;
                        ns.WriteTimeout = 1000;
                    }
                    NotifyPropertyChanged("IsConnect");
                    return connected;
                }
                
            }
            NotifyPropertyChanged("IsConnect");
            return false;
            

        }
        public async Task<bool> ConnectAsync(string ip, int port, int times = 5)
        {
            if (client == null)
                client = new TcpClient();
            if (!IsConnect)
            {
                DisConnect();
                client = new TcpClient();
                client.ReceiveTimeout = 1000;
                client.SendTimeout = 1000;
                bool connected = await TcpAsyncConnect.ConnectAsync(client, ip, port, times);

                if (IsConnect)
                {
                    ns = client.GetStream();
                    ns.ReadTimeout = 1000;
                    ns.WriteTimeout = 1000;
                }
                NotifyPropertyChanged("IsConnect");
                return connected;
            }
            NotifyPropertyChanged("IsConnect");
            return false;
        }

        private bool ClientIsConnect()
        {
            if (client == null || client.Client == null)
                return false;
            return  client.Client.Connected && client.Connected;
        }

        public void DisConnect()
        {
            if(ns != null)
                ns.Close();
            if(client.Client != null)
                client.Client.Close();
            client.Close();
            NotifyPropertyChanged("IsConnect");
        }

        public event PropertyChangedEventHandler PropertyChanged;
        // This method is called by the Set accessor of each property.
        // The CallerMemberName attribute that is applied to the optional propertyName
        // parameter causes the property name of the caller to be substituted as an argument.
        private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
